if (SERVER) then
	AddCSLuaFile("shared.lua")
end

if (CLIENT) then
	SWEP.PrintName = "Keypad Cracker"
	SWEP.Slot = 4
	SWEP.SlotPos = 1
	SWEP.DrawAmmo = false
	SWEP.DrawCrosshair = true
end

-- Variables that are used on both client and server

SWEP.Author = "Chief Tiger, modified by khm (aka HellRazor)"
SWEP.Instructions = "Left click to crack a keypad"
SWEP.Contact = ""
SWEP.Purpose = ""

SWEP.ViewModelFOV = 62
SWEP.ViewModelFlip = false
SWEP.ViewModel = Model("models/weapons/v_c4.mdl")
SWEP.WorldModel = Model("models/weapons/w_c4.mdl")

SWEP.Spawnable = false
SWEP.AdminSpawnable = true

SWEP.Sound = Sound("weapons/deagle/deagle-1.wav")

SWEP.Primary.ClipSize = -1      -- Size of a clip
SWEP.Primary.DefaultClip = 0        -- Default number of bullets in a clip
SWEP.Primary.Automatic = false      -- Automatic/Semi Auto
SWEP.Primary.Ammo = ""

SWEP.Secondary.ClipSize = -1        -- Size of a clip
SWEP.Secondary.DefaultClip = -1     -- Default number of bullets in a clip
SWEP.Secondary.Automatic = false        -- Automatic/Semi Auto
SWEP.Secondary.Ammo = ""
SWEP.CrackableKeypadClasses = {"sent_keypad", "sent_keypad_wire"}

SWEP.KeyCrackTime = {["Min"] = 30, ["Max"] = 60} -- The minimum and maximum amount of time that is randomly chosen between to determine how long it takes to crack a keypad
SWEP.MaxDistance = 50 -- The maximum distance that one can be away from from the keypad and still crack it
SWEP.KeypadCrackFailOdds = {1, 4} -- The odds of the cracker failing and triggering the deny function of the keypad instead of the success
	-- Examples:	{1, 4} = 25% chance of failing
	--				{3, 4) = 75%
	--				{1, 2} = 50%

/*---------------------------------------------------------
Name: SWEP:Initialize()
Desc: Called when the weapon is first loaded
---------------------------------------------------------*/
function SWEP:Initialize()
	if (SERVER) then
		self:SetWeaponHoldType("normal")
	end
end

function SWEP:SetupDataTables()
	self:DTVar("Bool", false, "IsCracking")
	self:DTVar("Int", 0, "CrackTime")
	self:DTVar("Float", 0, "EndCrack")
end

/*---------------------------------------------------------
Name: SWEP:PrimaryAttack()
Desc: +attack1 has been pressed
---------------------------------------------------------*/

function SWEP:PrimaryAttack()
	self.Weapon:SetNextPrimaryFire(CurTime() + .4)
	if self.dt.IsCracking then return end

	local trace = self.Owner:GetEyeTrace()
	if ValidEntity(trace.Entity) and trace.HitPos:Distance(self.Owner:GetShootPos()) <= self.MaxDistance and table.HasValue(self.CrackableKeypadClasses, trace.Entity:GetClass()) then
		if SERVER then
			self.dt.IsCracking = true
			self.Cracking = trace.Entity
			self.dt.CrackTime = math.random(self.KeyCrackTime.Min, self.KeyCrackTime.Max)
			self.dt.EndCrack = CurTime() + self.dt.CrackTime
			self:SetWeaponHoldType("pistol")
			timer.Create("KeyCrackSounds", 1, self.dt.CrackTime, self.EmitSound, self, "buttons/blip2.wav", 100, 100)
		end
		/*if CLIENT then
			self.Dots = self.Dots or ""
			timer.Create("KeyCrackDots", 0.5, 0, 	function(wep) 
														if not wep:IsValid() then timer.Destroy("KeyCrackDots") return end
														local len = string.len(wep.Dots)
														local dots = {[0]=".", [1]="..", [2]="...", [3]=""}
														wep.Dots = dots[len]
													end, self)
		end*/
	end 
end

function SWEP:Holster()
	if SERVER then
		self.dt.IsCracking = false
		timer.Destroy("KeyCrackSounds")
	else
		timer.Destroy("KeyCrackDots")
	end
	return true
end

if SERVER then
	// These RunKeypad functions were copied from the Keypads actual RunKeypad functions
	function SWEP.RunKeypad(Repeats, Length, Delay, Key, Owner)
		for i = 0, Repeats do
			timer.Simple(Length*(i)+Delay*i, function () Owner:ConCommand("+gm_special "..Key.."\n") end)
			timer.Simple(Length*(i+1)+Delay*i, function () Owner:ConCommand("-gm_special "..Key.."\n") end)
		end
	end

	function SWEP.RunWireKeypad(Ent, Repeats, Length, Delay, Var, Owner, Toggle, ValueOn, ValueOff)
		for i = 0, Repeats do
			if (Toggle) then
				if (Ent.Outputs[Var].Value == ValueOff) then
					if (i%2 == 1) then
						timer.Simple(Delay*i, function() Wire_TriggerOutput(Ent, Var, ValueOff) end)
					else
						timer.Simple(Delay*i, function() Wire_TriggerOutput(Ent, Var, ValueOn) end)
					end
				else
					if (i%2 == 1) then
						timer.Simple(Delay*i, function() Wire_TriggerOutput(Ent, Var, ValueOn) end)
					else
						timer.Simple(Delay*i, function() Wire_TriggerOutput(Ent, Var, ValueOff) end)
					end
				end
			else
				timer.Simple(Length*(i)+Delay*i, function() Wire_TriggerOutput(Ent, Var, ValueOn) end)
				timer.Simple(Length*(i+1)+Delay*i, function() Wire_TriggerOutput(Ent, Var, ValueOff) end)
			end
		end
	end

	function SWEP:Succeed()
		self.dt.IsCracking = false
		if ValidEntity(self.Cracking) then
			if self.Cracking:GetClass() == "sent_keypad" then
				local owner = self.Cracking:GetNWEntity("keypad_owner")
				if self.Cracking:GetNetworkedBool("keypad_simple") then
					local Key = self.Cracking:GetNWInt("keypad_keygroup1")
					owner:ConCommand("+gm_special " .. Key .. "\n")
					timer.Simple(self.Cracking:GetNWInt("keypad_length1"), function() owner:ConCommand("-gm_special " .. Key .. "\n")end)
				else
					local InitDelay = self.Cracking:GetNetworkedInt("keypad_initdelay1")
					if InitDelay > 0 then
						timer.Simple(InitDelay, self.RunKeypad, self.Cracking:GetNetworkedInt("keypad_repeats1"), self.Cracking:GetNWInt("keypad_length1"), self.Cracking:GetNetworkedInt("keypad_delay1"), self.Cracking:GetNWInt("keypad_keygroup1"), owner)
					else
						self.RunKeypad(self.Cracking:GetNetworkedInt("keypad_repeats1"), self.Cracking:GetNWInt("keypad_length1"), self.Cracking:GetNetworkedInt("keypad_delay1"), self.Cracking:GetNWInt("keypad_keygroup1"), owner)
					end
				end
				self.Cracking:SetNWBool("keypad_access", true)
				self.Cracking:SetNWBool("keypad_showaccess", true)
				self.Cracking:EmitSound("buttons/button9.wav")
				timer.Simple(2, function() self.Cracking:SetNWBool("keypad_showaccess", false) end)
			elseif self.Cracking:GetClass() == "sent_keypad_wire" then
				local owner = self.Cracking:GetNWEntity("keypad_owner")
				local InitDelay = self.Cracking:GetNetworkedInt("keypad_initdelay1")
				if InitDelay > 0 then
					timer.Simple(InitDelay, self.RunWireKeypad, self.Cracking, self.Cracking:GetNetworkedInt("keypad_repeats1"), self.Cracking:GetNWInt("keypad_length1"), self.Cracking:GetNetworkedInt("keypad_delay1"), "Valid", owner, self.Cracking:GetNetworkedBool("keypad_toggle1"), self.Cracking:GetNetworkedInt("keypad_valueon1"), self.Cracking:GetNetworkedInt("keypad_valueoff1"))
				else
					self.RunWireKeypad(self.Cracking, self.Cracking:GetNetworkedInt("keypad_repeats1"), self.Cracking:GetNWInt("keypad_length1"), self.Cracking:GetNetworkedInt("keypad_delay1"), "Valid", owner, self.Cracking:GetNetworkedBool("keypad_toggle1"), self.Cracking:GetNetworkedInt("keypad_valueon1"), self.Cracking:GetNetworkedInt("keypad_valueoff1"))
				end
				self.Cracking:SetNWBool("keypad_access", true)
				self.Cracking:SetNWBool("keypad_showaccess", true)
				self.Cracking:EmitSound("buttons/button9.wav")
				timer.Simple(2, function() self.Cracking:SetNWBool("keypad_showaccess", false) end)
			end
		end
		timer.Destroy("KeyCrackSounds")
	end

	function SWEP:EpicFail()
		self.dt.IsCracking = false
		if ValidEntity(self.Cracking) then
			if self.Cracking:GetClass() == "sent_keypad" then
				local owner = self.Cracking:GetNWEntity("keypad_owner")
				if self.Cracking:GetNetworkedBool("keypad_simple") then
					local Key = self.Cracking:GetNWInt("keypad_keygroup2")
					owner:ConCommand("+gm_special " .. Key .. "\n")
					timer.Simple(self.Cracking:GetNWInt("keypad_length2"), function() owner:ConCommand("-gm_special " .. Key .. "\n")end)
				else
					local InitDelay = self.Cracking:GetNetworkedInt("keypad_initdelay2")
					if InitDelay > 0 then
						timer.Simple(InitDelay, self.RunKeypad, self.Cracking:GetNetworkedInt("keypad_repeats2"), self.Cracking:GetNWInt("keypad_length2"), self.Cracking:GetNetworkedInt("keypad_delay2"), self.Cracking:GetNWInt("keypad_keygroup2"), owner)
					else
						self.RunKeypad(self.Cracking:GetNetworkedInt("keypad_repeats2"), self.Cracking:GetNWInt("keypad_length2"), self.Cracking:GetNetworkedInt("keypad_delay2"), self.Cracking:GetNWInt("keypad_keygroup2"), owner)
					end
				end
				self.Cracking:SetNWBool("keypad_access", false)
				self.Cracking:SetNWBool("keypad_showaccess", true)
				self.Cracking:EmitSound("buttons/button11.wav")
				timer.Simple(2, function() self.Cracking:SetNWBool("keypad_showaccess", false) end)
			elseif self.Cracking:GetClass() == "sent_keypad_wire" then
				local owner = self.Cracking:GetNWEntity("keypad_owner")
				local InitDelay = self.Cracking:GetNetworkedInt("keypad_initdelay2")
				if InitDelay > 0 then
					timer.Simple(InitDelay, self.RunWireKeypad, self.Cracking, self.Cracking:GetNetworkedInt("keypad_repeats2"), self.Cracking:GetNWInt("keypad_length2"), self.Cracking:GetNetworkedInt("keypad_delay2"), "Invalid", owner, self.Cracking:GetNetworkedBool("keypad_toggle2"), self.Cracking:GetNetworkedInt("keypad_valueon2"), self.Cracking:GetNetworkedInt("keypad_valueoff2"))
				else
					self.RunWireKeypad(self.Cracking, self.Cracking:GetNetworkedInt("keypad_repeats2"), self.Cracking:GetNWInt("keypad_length2"), self.Cracking:GetNetworkedInt("keypad_delay2"), "Invalid", owner, self.Cracking:GetNetworkedBool("keypad_toggle2"), self.Cracking:GetNetworkedInt("keypad_valueon2"), self.Cracking:GetNetworkedInt("keypad_valueoff2"))
				end
				self.Cracking:SetNWBool("keypad_access", false)
				self.Cracking:SetNWBool("keypad_showaccess", true)
				self.Cracking:EmitSound("buttons/button11.wav")
				timer.Simple(2, function() self.Cracking:SetNWBool("keypad_showaccess", false) end)
			end
		end
		timer.Destroy("KeyCrackSounds")
	end

	function SWEP:Fail()
		self.dt.IsCracking	= false
		self:SetWeaponHoldType("normal")
		timer.Destroy("KeyCrackSounds")
	end
end

if SERVER then
	function SWEP:Think()
		if self.dt.IsCracking then
			local trace = self.Owner:GetEyeTrace()
			if not ValidEntity(trace.Entity) || trace.Entity ~= self.Cracking || trace.HitPos:Distance(self.Owner:GetShootPos()) > self.MaxDistance then
				self:Fail()
			end
			if self.dt.EndCrack <= CurTime() then
				if self.KeypadCrackFailOdds[1] >= 1 && self.KeypadCrackFailOdds[2] >= 1 && math.random(1, self.KeypadCrackFailOdds[2]) <= self.KeypadCrackFailOdds[1] then
					self:EpicFail()
				else
					self:Succeed()
				end
			end
		end
	end
else
	function SWEP:DrawHUD()
		if self.dt.IsCracking then
			self.Dots = self.Dots or ""
			local w = ScrW()
			local h = ScrH()
			local x,y,width,height = w/2-w/10, h/ 2, w/5, h/15
			draw.RoundedBox(8, x, y, width, height, Color(10,10,10,120))
			
			local curtime = CurTime() - (self.dt.EndCrack - self.dt.CrackTime)
			local status = curtime/self.dt.CrackTime
			local BarWidth = status * (width - 32) + 16
			draw.RoundedBox(8, x+8, y+8, BarWidth, height - 16, Color(255-(status*255), 0+(status*255), 0, 255))
			
			local Dots = string.rep(".", curtime % 3)
			draw.SimpleText("Cracking" .. Dots, "Trebuchet24", w/2, h/2 + height/2, Color(255,255,255,255), 1, 1)
		end
	end
end

function SWEP:SecondaryAttack()
	self:PrimaryAttack()
end